package com.semidata.trp.report.report;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;

import org.apache.ibatis.session.SqlSession;

import com.semidata.rtd.core.log.Logger;
import com.semidata.trp.report.config.Config;
import com.semidata.trp.report.mapper.NRTReportMapper;
import com.semidata.trp.report.utils.SessionUtils;

public class NRTRecompute {
	private Map<String, PersonalData> personalDatas = new TreeMap<>();
	// private ReportData reportData;
	private static Map<String, String> positionMedia = new HashMap<String, String>();
	private static List<Integer> orgList = new ArrayList<Integer>();
	private static List<Integer> straList = new ArrayList<Integer>();
	private static List<Integer> resList = new ArrayList<Integer>();
	List<String> machineList = new ArrayList<String>();
	List<String> files = new ArrayList<String>();
	private static Config config = Config.getConfig();
	private static Map<String, Integer> B64 = new HashMap<String, Integer>();
	private static String[] headList = { "+", "-", "0", "1", "2", "3", "4",
			"5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
			"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
			"V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h",
			"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
			"v", "w", "x", "y", "z" };

	public NRTRecompute() {
		for (int i = 0; i < headList.length; i++) {
			B64.put(headList[i], i);
		}
	}
	/*
	public static Map<String, String> mysplit(String line) {
		String url = null;
		try {
			url = URLDecoder.decode(line, "utf-8");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		int lp = url.indexOf('?');
		url = url.substring(lp + 1);
		Map<String, String> result = new HashMap<String, String>();
		String[] resultArray = url.split("\\&");
		if (resultArray.length < 10) {
			return null;
		}
		int tag = 0;
		String key, value;
		for (int i = 0; i < resultArray.length; i++) {
			tag = resultArray[i].indexOf("=");
			if (tag == -1)
				continue;
			key = resultArray[i].substring(0, tag);
			value = resultArray[i].substring(tag + 1);
			result.put(key, value);
		}
		resultArray = null;
		if (result.get("a") == null || result.get("p") == null
				|| result.get("r") == null || result.get("s") == null
				|| result.get("m") == null || result.get("t") == null
				|| result.get("b") == null || result.get("i") == null
				|| result.get("u") == null || result.get("mt") == null) {
			return null;
		}
		if ((straList.indexOf(Integer.valueOf(result.get("s"))) == -1)
				|| (orgList.indexOf(Integer.valueOf(result.get("a"))) == -1)
				|| (positionMedia.get(result.get("p")) == null)
				|| (resList.indexOf(Integer.valueOf(result.get("r"))) == -1)) {
			return null;
		}
		return result;
	}
	*/
	public void readFile(String fileName) throws Exception {
		File file = new File(fileName);
		if (!file.exists() || !file.canRead()) {
			throw new Exception("read file error");
		}
		BufferedReader br = new BufferedReader(new FileReader(file));
		String tmpLine = br.readLine();
		int sid, rid, pid, orgId, mediaId, mediaType, head, lp;
		double cost;
		String uid, key, value, url = null;
		Map<String, String> result;
		int tag = 0;
		PersonalData personalData;
		result = new HashMap<String, String>();

		String[] resultArray;

		while (tmpLine != null) {
			head = tmpLine.indexOf("/r.gif");
			if (head == 0) {
				tag = 1;
			} else {
				head = tmpLine.indexOf("/a.gif");
				if (head == 0) {
					tag = 0;
				}
			}
			if (head == 0) {
				// result = mysplit(tmpLine);
				try {
					url = URLDecoder.decode(tmpLine, "utf-8");
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					continue;
				}
				lp = url.indexOf('?');
				url = url.substring(lp + 1);
				resultArray = url.split("\\&");
				if (resultArray.length < 10) {
					continue;
				}
				for (int i = 0; i < resultArray.length; i++) {
					tag = resultArray[i].indexOf("=");
					if (tag == -1)
						continue;
					key = resultArray[i].substring(0, tag);
					value = resultArray[i].substring(tag + 1);
					result.put(key, value);
				}
				resultArray = null;
				if (result.get("a") == null || result.get("p") == null
						|| result.get("r") == null || result.get("s") == null
						|| result.get("m") == null || result.get("t") == null
						|| result.get("b") == null || result.get("i") == null
						|| result.get("u") == null || result.get("mt") == null) {
					continue;
				}
				if ((straList.indexOf(Integer.valueOf(result.get("s"))) == -1)
						|| (orgList.indexOf(Integer.valueOf(result.get("a"))) == -1)
						|| (positionMedia.get(result.get("p")) == null)
						|| (resList.indexOf(Integer.valueOf(result.get("r"))) == -1)) {
					continue;
				}
				uid = result.get("u");
				if (personalDatas.get(uid) == null) {
					if(personalDatas.size() % 10000 == 0)
						Logger.log("DEBUG", String.valueOf(personalDatas.size()));
					personalDatas.put(uid, new PersonalData());
				}
				personalData = personalDatas.get(uid);
				try {
					sid = Integer.valueOf(result.get("s"));
					rid = Integer.valueOf(result.get("r"));
					pid = Integer.valueOf(result.get("p"));
					orgId = Integer.valueOf(result.get("a"));
					mediaId = Integer
							.valueOf(positionMedia.get(result.get("p")));
					mediaType = Integer.valueOf(result.get("mt"));
					cost = Double.valueOf(result.get("b")) / 1000;
				} catch (Exception e) {
					continue;
				}
				if (tag == 1) {
					personalData.addTotalReportClick(1);
					personalData.addMediaReportClick(mediaId, 1);
					personalData.addResReportClick(rid, 1);
					personalData.addMediaTypeReportClick(mediaType, 1);
					personalData.addPosReportClick(pid, 1);
					personalData.addOrgReportClick(orgId, 1);
					personalData.addOrgMediaReportClick(orgId, mediaId, 1);
					personalData
							.addOrgMediaTypeReportClick(orgId, mediaType, 1);
					personalData.addOrgPosReportClick(orgId, pid, 1);
					personalData.addOrgStraReportClick(orgId, sid, 1);
					personalData.addOrgResReportClick(orgId, rid, 1);
					personalData.addStraPosReportClick(sid, pid, 1);
					personalData.addStraResReportClick(sid, rid, 1);
					personalData.addStraMediaTypeReportClick(sid, mediaType, 1);
				} else {
					personalData.addTotalReportPv(1);
					personalData.addMediaReportPv(mediaId, 1);
					personalData.addResReportPv(rid, 1);
					personalData.addMediaTypeReportPv(mediaType, 1);
					personalData.addPosReportPv(pid, 1);
					personalData.addOrgReportPv(orgId, 1);
					personalData.addOrgMediaReportPv(orgId, mediaId, 1);
					personalData.addOrgMediaTypeReportPv(orgId, mediaType, 1);
					personalData.addOrgPosReportPv(orgId, pid, 1);
					personalData.addOrgStraReportPv(orgId, sid, 1);
					personalData.addOrgResReportPv(orgId, rid, 1);
					personalData.addStraPosReportPv(sid, pid, 1);
					personalData.addStraResReportPv(sid, rid, 1);
					personalData.addStraMediaTypeReportPv(sid, mediaType, 1);
					personalData.addTotalReportCost(cost);
					personalData.addMediaReportCost(mediaId, cost);
					personalData.addResReportCost(rid, cost);
					personalData.addMediaTypeReportCost(mediaType, cost);
					personalData.addPosReportCost(pid, cost);
					personalData.addOrgReportCost(orgId, cost);
					personalData.addOrgMediaReportCost(orgId, mediaId, cost);
					personalData.addOrgMediaTypeReportCost(orgId, mediaType,
							cost);
					personalData.addOrgPosReportCost(orgId, pid, cost);
					personalData.addOrgResReportCost(orgId, rid, cost);
					personalData.addOrgStraReportCost(orgId, sid, cost);
					personalData.addStraPosReportCost(sid, pid, cost);
					personalData.addStraResReportCost(sid, rid, cost);
					personalData.addStraMediaTypeReportCost(sid, mediaType,
							cost);
				}
				personalDatas.put(uid, personalData);
			}
			tmpLine = br.readLine();
		}
		br.close();
		personalData = null;
		result = null;
		br = null;
	}

	public void run() throws Exception {
		for (int i = 0; i < files.size(); i++) {
			try {
				readFile(files.get(i));
			} catch (Exception e) {
				e.printStackTrace();
				throw e;
			}
		}
	}

	public List<String> getFilesByDay(String date, boolean ignore)
			throws Exception {
		List<String> files = new ArrayList<String>();
		String root = config.getMonitorLogDir();
		StringBuffer basePath = new StringBuffer(root);
		basePath.append("/");
		basePath.append(date);
		// basePath.concat("/");
		// basePath.concat(machineIdList[i]);
		File dir = new File(basePath.toString());
		if (!dir.isDirectory() || !dir.exists()) {
			if (ignore) {
				throw new Exception("dir error:" + date);
			}
		} else {
			File[] fileList = dir.listFiles();
			if (fileList == null || fileList.length <= 0) {
				if (ignore) {
					throw new Exception("empty dir:" + date);
				}
			} else {
				Map<String, List<File>> logFilesByMachine = new HashMap<String, List<File>>();
				for (int i = 0; i < fileList.length; i++) {
					String filename = fileList[i].getName();
					if (filename.endsWith(".log")) {
						int lp = filename.indexOf('.');
						int lt = filename.indexOf('.', lp + 1);
						String tag = filename.substring(lp + 1, lt);
						if (machineList.indexOf(tag) >= 0) {
							if (logFilesByMachine.get(tag) == null) {
								logFilesByMachine.put(tag,
										new ArrayList<File>());
							}
							logFilesByMachine.get(tag).add(fileList[i]);
						}
					}
				}
				if (ignore) {
					for (String id : machineList) {
						if (logFilesByMachine.get(id).size() < 1440) {
							throw new Exception("lost file:" + date);
						}
					}
				}

				for (Map.Entry<String, List<File>> entry : logFilesByMachine
						.entrySet()) {
					List<File> entryFiles = new ArrayList<File>();
					entryFiles = entry.getValue();

					for (int j = 0; j < entryFiles.size(); j++) {
						files.add(entryFiles.get(j).getAbsolutePath());
					}

				}
			}
		}
		basePath = null;
		return files;
	}

	public String getFirstDayOf7Days(String date) {
		SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMdd");
		Calendar c = new GregorianCalendar();
		c.set(Integer.valueOf(date.substring(0, 4)),
				Integer.valueOf(date.substring(4, 6)) - 1,
				Integer.valueOf(date.substring(6)) - 6);
		String firstDayOf7Days = dateformat.format(c.getTime());
		dateformat = null;
		c = null;
		return firstDayOf7Days;
	}

	public void setFileList(String date, boolean ignore) throws Exception {
		files = new ArrayList<>();
		personalDatas = new TreeMap<>();

		setAllList(date);
		if (date.length() != 8) {
			throw new Exception("error pram!");
		}

		List<String> days = new ArrayList<String>();
		days.add(date);
		try {
			for (int i = 0; i < days.size(); i++) {
				files.addAll(getFilesByDay(days.get(i), ignore));
			}
		} catch (Exception e) {
			throw e;
		}
		days = null;
		run();
		update(date);
		clear();
	}

	private void clear() {
		// TODO Auto-generated method stub
		files = null;
		personalDatas = null;
		machineList = null;
		orgList = null;
		positionMedia = null;
		straList = null;
		resList = null;
	}

	public Map<String, String> getPositionMedia() {
		return positionMedia;
	}

	public void setAllList(String date) {
		List<Map<String, Integer>> posMedia = new ArrayList<Map<String, Integer>>();
		SqlSession session = SessionUtils.getSession();
		/*
		 * orgList = new ArrayList<Integer>(); straList = new
		 * ArrayList<Integer>(); resList = new ArrayList<Integer>(); machineList
		 * = new ArrayList<String>();
		 */
		positionMedia = new HashMap<>();
		try {
			NRTReportMapper mapper = session.getMapper(NRTReportMapper.class);
			posMedia = mapper.getAllMediaByPosition();
			orgList = mapper.getAllOrgId();
			straList = mapper.getAllStraId(date);
			resList = mapper.getAllResourceId(date);
			machineList = mapper.getMonitorServerList();
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
			session.rollback();
		} finally {
			session.close();
		}
		for (Map<String, Integer> posMediaIt : posMedia) {
			// String id = String.valueOf(posMediaIt.get("id"));
			// String media_id = String.valueOf(posMediaIt.get("media_id"));
			// System.out.println(id);
			// System.out.println(media_id);
			positionMedia.put(String.valueOf(posMediaIt.get("id")),
					String.valueOf(posMediaIt.get("media_id")));
		}
		posMedia = null;
	}

	public void update(String date) throws Exception {
		// uid : pv;click;cost,
		// {[mediaId,pv;click;cost][]}

		// {[mediaType,pv;click;cost][]} 新增

		// {[posId,pv;click;cost][]}
		// 废弃{(straId,[posId,pv;click;cost][])()}

		// 废弃{(straId,[mediaType,pv;click;cost][])()} 新增

		// {<straId,([posId,pv;click;cost][])([mediaType,pv;click;cost][])([resId,pv;click;cost][])><>}

		// 废弃{<orgId,pv;click;cost,([mediaId,pv;click;cost][])([posId,pv;click;cost][])([straId,pv;click;cost][])><>}
		// {<orgId,pv;click;cost,([mediaId,pv;click;cost][])([posId,pv;click;cost][])([straId,pv;click;cost][])([mediaType,pv;click;cost][])([resId,pv;click;cost][])><>}

		// 废弃{(orgId,[mediaType,pv;click;cost][])()} 新增

		// {[resId,pv;click;cost][]}

		Logger.log("DEBUG", "start write");
		String rootDir = config.getReportDir();
		File file = new File(rootDir);
		if (!file.exists()) {
			file.mkdirs();
		}
		file = null;
		rootDir = rootDir.concat("/");
		rootDir = rootDir.concat(date);
		StringBuffer sb = new StringBuffer();
		FileWriter[] fileWriters = new FileWriter[B64.size()];
		for (int i = 0; i < B64.size(); i++) {
			sb.setLength(0);
			sb.append(rootDir);
			sb.append(".");
			sb.append(headList[i]);
			sb.append(".log");
			fileWriters[i] = new FileWriter(sb.toString());
			Logger.log("DEBUG", sb.toString());
		}

		String head;
		PersonalData personalData;
		ReportUnit reportUnit;
		Map<Integer, ReportUnit> resReport = null, mediaTypeReport = null, posReport = null;
		Map<Integer, ReportUnit> straReport = null, mediaReport = null;
		for (Map.Entry<String, PersonalData> entryPersonalData : personalDatas
				.entrySet()) {
			Logger.log("DEBUG", entryPersonalData.getKey());
			if (entryPersonalData.getKey().length() < 1)
				continue;
			head = entryPersonalData.getKey().substring(0, 1);
			personalData = entryPersonalData.getValue();
			reportUnit = personalData.getTotalReport();
			sb.setLength(0);

			// uid : pv;click;cost,
			sb.append(entryPersonalData.getKey());
			sb.append(":");
			sb.append(reportUnit.getPv());
			sb.append(";");
			sb.append(reportUnit.getClick());
			sb.append(";");
			sb.append(reportUnit.getCost());
			sb.append(",");

			// {[mediaId,pv;click;cost][]}
			sb.append("{");
			for (Map.Entry<Integer, ReportUnit> entryReport : personalData
					.getMediaReport().entrySet()) {
				reportUnit = entryReport.getValue();
				sb.append("[");
				sb.append(entryReport.getKey());
				sb.append(",");
				sb.append(reportUnit.getPv());
				sb.append(";");
				sb.append(reportUnit.getClick());
				sb.append(";");
				sb.append(reportUnit.getCost());
				sb.append("]");
			}
			sb.append("}{");

			// {[mediaType,pv;click;cost][]} 新增
			for (Map.Entry<Integer, ReportUnit> entryReport : personalData
					.getMediaTypeReport().entrySet()) {
				reportUnit = entryReport.getValue();
				sb.append("[");
				sb.append(entryReport.getKey());
				sb.append(",");
				sb.append(reportUnit.getPv());
				sb.append(";");
				sb.append(reportUnit.getClick());
				sb.append(";");
				sb.append(reportUnit.getCost());
				sb.append("]");
			}
			sb.append("}{");

			// {[posId,pv;click;cost][]}
			for (Map.Entry<Integer, ReportUnit> entryReport : personalData
					.getPosReport().entrySet()) {
				reportUnit = entryReport.getValue();
				sb.append("[");
				sb.append(entryReport.getKey());
				sb.append(",");
				sb.append(reportUnit.getPv());
				sb.append(";");
				sb.append(reportUnit.getClick());
				sb.append(";");
				sb.append(reportUnit.getCost());
				sb.append("]");
			}
			sb.append("}{");

			// {<straId,([posId,pv;click;cost][])([mediaType,pv;click;cost][])([resId,pv;click;cost][])><>}
			resReport = null;
			mediaTypeReport = null;
			posReport = null;
			for (Entry<Integer, Map<Integer, ReportUnit>> entryReport : personalData
					.getStraResReport().entrySet()) {
				sb.append("<");
				sb.append(entryReport.getKey());
				sb.append(",(");

				posReport = personalData.getStraPosReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : posReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")(");

				mediaTypeReport = personalData.getStraMediaTypeReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : mediaTypeReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")(");

				resReport = personalData.getStraResReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : resReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")");
				sb.append(">");
			}
			sb.append("}{");

			// {<orgId,pv;click;cost,([mediaId,pv;click;cost][])([posId,pv;click;cost][])([straId,pv;click;cost][])([mediaType,pv;click;cost][])([resId,pv;click;cost][])><>}
			straReport = null;
			mediaReport = null;
			for (Map.Entry<Integer, ReportUnit> entryReport : personalData
					.getOrgReport().entrySet()) {
				reportUnit = entryReport.getValue();
				sb.append("<");
				sb.append(entryReport.getKey());
				sb.append(",");
				sb.append(reportUnit.getPv());
				sb.append(";");
				sb.append(reportUnit.getClick());
				sb.append(";");
				sb.append(reportUnit.getCost());
				sb.append(",(");

				mediaReport = personalData.getOrgMediaReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : mediaReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")(");

				posReport = personalData.getOrgPosReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : posReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")(");

				straReport = personalData.getOrgStraReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : straReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")(");

				mediaTypeReport = personalData.getOrgMediaTypeReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : mediaTypeReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")(");

				resReport = personalData.getOrgResReport().get(
						entryReport.getKey());
				for (Map.Entry<Integer, ReportUnit> reportEntry : resReport
						.entrySet()) {
					reportUnit = reportEntry.getValue();
					sb.append("[");
					sb.append(reportEntry.getKey());
					sb.append(",");
					sb.append(reportUnit.getPv());
					sb.append(";");
					sb.append(reportUnit.getClick());
					sb.append(";");
					sb.append(reportUnit.getCost());
					sb.append("]");
				}
				sb.append(")");
				sb.append(">");
			}
			sb.append("}{");

			// {[resId,pv;click;cost][]}
			for (Map.Entry<Integer, ReportUnit> entryReport : personalData
					.getResReport().entrySet()) {
				reportUnit = entryReport.getValue();
				sb.append("[");
				sb.append(entryReport.getKey());
				sb.append(",");
				sb.append(reportUnit.getPv());
				sb.append(";");
				sb.append(reportUnit.getClick());
				sb.append(";");
				sb.append(reportUnit.getCost());
				sb.append("]");
			}
			sb.append("}\n");
			if (B64.get(head) != null) {
				fileWriters[B64.get(head)].write(sb.toString());
			}
		}
		for (int i = 0; i < fileWriters.length; i++) {
			fileWriters[i].close();
		}
		sb = null;
		fileWriters = null;
	}

	public static void main(String[] args) {
		NRTRecompute nc = new NRTRecompute();
		nc.personalDatas = new TreeMap<>();
		final Random rand = new Random();
		for (int i = 0; i < 100000; i++) {
			nc.personalDatas.put(String.valueOf(rand.nextInt(100000)),
					new PersonalData());
		}
		System.out.println("over");
	}

}
